package rdbms.ddl;
import rdbms.RDBMS;
import valuetypes.BooleanValue;
import valuetypes.CharacterValue;
import valuetypes.DBValue;
import valuetypes.NumericValue;
import valuetypes.ValueType;
import exception.DBValueException;
import exception.IllegalNameException;
import exception.InvalidFieldException;
import exception.NoSuchDatabaseException;


public class Field {
	private Table table;
	private NumericValue fieldId;
	private CharacterValue fieldName;
	private BooleanValue fieldNullable;
	private ValueType fieldType;
//	private int index;
		
	public Field( String name, ValueType type, boolean nullable) throws DBValueException, IllegalNameException{
//		this.parent = table;
		this.fieldName = new CharacterValue( name );
		this.fieldType = type;
		fieldNullable = new BooleanValue(nullable);
//		enforceUnique = new BooleanValue(unique);
//		this.index = parent.addField(this);
	}
	
	public Field( String name, ValueType type) throws DBValueException, IllegalNameException{
//		this.parent = table;
		this.fieldName = new CharacterValue( name );
		this.fieldType = type;
		fieldNullable = new BooleanValue(true);
//		enforceUnique = new BooleanValue(false);
//		this.index = parent.addField(this);
	}

	public String getName() {
		return fieldName.toString();
	}

	public boolean isValidValue(DBValue value, Table table) {
		if(value.getClass().equals(fieldType.getBaseClass())){			
			if(value == null || value.isNull()){
				if(fieldNullable.getBool()){
					return true;
				}
				else return false;
			}
			else return true;
		}
		return false;
	}

	public ValueType getFieldType(){
		return fieldType;
	}

	public byte[] serialize() throws DBValueException {
		return DBValue.valuesAsData(fieldId,  table.getDatabase().getId(), table.getId(), fieldName, new CharacterValue(fieldType.name()), fieldNullable);		
	}

	public void setTable(Table table, int id) throws InvalidFieldException {
//		if(fieldId == null){
			fieldId = new NumericValue(id);
			this.table= table; 
//		}
//		else throw InvalidFieldException.IdAlreadySet(id, fieldId.getValue(), fieldName.toString());		
	}

	public NumericValue getId() {
		return fieldId;
	}
	
	public static Field inflateFieldData(byte[] data, RDBMS rdbms) throws DBValueException, IllegalNameException, NoSuchDatabaseException, InvalidFieldException {
		int offset = 0;
		
		NumericValue fieldId = new NumericValue(data, offset);
		offset += fieldId.getSize();
		
		NumericValue dbId = new NumericValue(data, offset);
		offset += dbId.getSize();
		
		NumericValue tableId = new NumericValue(data, offset);
		offset += tableId.getSize();
		
		CharacterValue fName = new CharacterValue(data, offset);
		offset += fName.getSize();
		
		CharacterValue charType = new CharacterValue(data, offset);
		ValueType type = ValueType.Numeric;
		try{
			 type = ValueType.valueOf(charType.toString());		
		}
		catch(IllegalArgumentException ex){
			System.out.println("endl?");
		}
		offset += charType.getSize();
		
//		BooleanValue fUnique = new BooleanValue(data, offset);
//		offset += fUnique.getSize();
		
		BooleanValue fNullable = new BooleanValue(data, offset);
		offset += fNullable.getSize();
		
		Field field = new Field(fName.toString(), type, fNullable.getBool());
		Database db = rdbms.getDatabase(dbId);
		Table table = db.getTable(tableId);
		table.addField(field);
		return field;
	}
	
	@Override
	public String toString() {
		String s = "";
		String nul = "NULL\t| ";
		if(fieldId == null)s += nul;
		else s += fieldId + "\t| ";
		
		if(table == null)s += nul;
		else s += table.getDatabase().getId() + "\t| "+
					table.getId() + "\t| ";
		
		if(fieldName == null)s += nul;
		else s += fieldName + "\t| " ;
		
		if(fieldType == null)s += nul;
		else s += fieldType + "\t| ";
		
		if(fieldNullable == null) s += nul;
		else s += fieldNullable;
		
		return s;
	}

	public boolean isNullable() {
		return fieldNullable.getBool();
	}
}
